/*	
 *				
 *					ISNW ---- It is a war.It is not warcraft!
 *
 *
 *					Author:					zhoukeli(haxixi_keli)
 *					Filename:				TerrainSceneNode.h
 *					CreateTime:				2008/12/31
 *					ModifyTime:				2008/12/31
 *
 */

#ifndef __ISNW_TERRAIN_SCENE_NODE_H__
#define __ISNW_TERRAIN_SCENE_NODE_H__

#include "include/ITerrainSceneNode.h"
#include "MeshBuffer.h"

namespace ISNW
{
namespace scene
{
	enum E_PATCH_SIZE
	{
		E_PS_5 = 5,
		E_PS_9 = 9,
		E_PS_17 = 17,
		E_PS_33 = 33,
		E_PS_65 = 65,
		E_PS_129 = 129,
	};

	class TerrainSceneNode : public ITerrainSceneNode
	{
	public:
		TerrainSceneNode(ISceneManager* sm,ISceneNode* parent,s32 id,u32 MLOD,E_PATCH_SIZE ps,s32 SFactor,core::vector3df pos,
			core::vector3df rotate,core::vector3df scale)
			:ITerrainSceneNode(sm,parent,id,pos,rotate,scale)
			,TerrainData(ps,MLOD,pos,rotate,scale)
			,oldCameraPosition(core::vector3df(0,0,0))
			,oldCameraRotation(core::vector3df(0,0,0))
			,SmoothFactor(SFactor)
		{
		}

	public:

		bool loadHeightMap(io::IReadFile* rfile,video::color32 vetexColor,s32 smoothFactor);

		void render();

		void onRegisterSceneNode();

		virtual u32 getMaterialCount() const
		{
			return 1;
		}

		virtual video::material& getMaterial(u32 idx)
		{
			return Material;
		}

		virtual void setMaterial(u32 stage,video::material m)
		{
			Material.removeAllTexture();

			Material = m;
		}

		virtual void setMaterialTexture(u32 stage,video::ITexture* texture)
		{
			for(u32 i = 0; i < getMaterialCount(); ++i)
			{
				getMaterial(i).setTexture(stage,texture);
			}
		}

		virtual core::aabbox3df getBoundBox() const
		{
			return TerrainData.BoundingBox;
		}

	protected:
		void calculateNormals(MeshBuffer*);

		void calculateLodDistanceThreshold();

		void createPatches();

		void calculatePatchData();

		void calculatePatchLOD();

		void calculateIndices();

		s32 getindex(u32 patchi,u32 patchj,u32 idx,u32 i,u32 j);

	public:
		struct SPatch
		{
			SPatch():CurrentLOD(-1),BoundingBox(core::vector3df(0,0,0)),Center(0,0,0),Top(0),Left(0),Bottom(0),Right(0){}
			s32 CurrentLOD;
			core::aabbox3df BoundingBox;
			core::vector3df Center;

			SPatch*	Top;
			SPatch*	Left;
			SPatch*	Bottom;
			SPatch*	Right;
		};

		struct STerrainData
		{
			STerrainData():Size(0),PatchSize(0),CalcPatchSize(0),MaxLOD(0),PatchCount(0),
				LODDistanceThreshold(0),Patches(0){}

			STerrainData(E_PATCH_SIZE patchsize,s32 mlod,core::vector3df pos,core::vector3df rot,core::vector3df sc)
				:PatchSize(patchsize),MaxLOD(mlod),Position(pos),Rotation(rot),Scale(sc)
				,Size(0),PatchCount(0),LODDistanceThreshold(0),Patches(0)
				,CalcPatchSize(patchsize-1){}

			s32	Size;
			core::vector3df	Position;
			core::vector3df	Rotation;
			core::vector3df	Scale;

			core::vector3df	RotaionPivot;

			core::vector3df	Center;

			s32	PatchSize;
			s32	CalcPatchSize;
			s32	PatchCount;
			s32	MaxLOD;

			core::aabbox3df	BoundingBox;

			f64*	LODDistanceThreshold;
			SPatch*	Patches;
		};

		STerrainData	TerrainData;

		MeshBuffer	RenderBuffer;

		u32	VerticesToRender;
		u32	IndicesToRender;

		core::vector3df		oldCameraPosition;
		f32	CameraMovementDelt;

		core::vector3df		oldCameraRotation;
		f32	CameraRotationDelt;

		core::string		HeightMapFile;

		s32	SmoothFactor;

		video::material		Material;

	};
} // end namespace scene
} // end namespace ISNW
#endif